﻿using System;
using System.Security.Cryptography;
using System.Text;
using Dimebrain.TweetSharp.Model;

/*
 *   Writen by: Martijn Dijksterhuis
 *   Code taken from: http://www.dijksterhuis.org/encrypting-decrypting-string/
 */ 

namespace Twipler.WebApp
{
	public static class Encryption
	{
		public static string EncryptString(string plainText, string passphrase)
		{
			byte[] results;
			System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding();

			// Step 1. We hash the passphrase using MD5
			// We use the MD5 hash generator as the result is a 128 bit byte array
			// which is a valid length for the TripleDES encoder we use below

			MD5CryptoServiceProvider hashProvider = new MD5CryptoServiceProvider();
			byte[] tdesKey = hashProvider.ComputeHash(utf8.GetBytes(passphrase));

			// Step 2. Create a new TripleDESCryptoServiceProvider object
			TripleDESCryptoServiceProvider tdesAlgorithm = new TripleDESCryptoServiceProvider();

			// Step 3. Setup the encoder
			tdesAlgorithm.Key = tdesKey;
			tdesAlgorithm.Mode = CipherMode.ECB;
			tdesAlgorithm.Padding = PaddingMode.PKCS7;

			// Step 4. Convert the input string to a byte[]
			byte[] dataToEncrypt = utf8.GetBytes(plainText);

			// Step 5. Attempt to encrypt the string
			try
			{
				ICryptoTransform encryptor = tdesAlgorithm.CreateEncryptor();
				results = encryptor.TransformFinalBlock(dataToEncrypt, 0, dataToEncrypt.Length);
			}
			finally
			{
				// Clear the TripleDes and Hashprovider services of any sensitive information
				tdesAlgorithm.Clear();
				hashProvider.Clear();
			}

			// Step 6. Return the encrypted string as a base64 encoded string
			return Convert.ToBase64String(results);
		}

		public static string DecryptString(string encryptedText, string passphrase)
		{
			byte[] results;
			System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding();

			// Step 1. We hash the passphrase using MD5
			// We use the MD5 hash generator as the result is a 128 bit byte array
			// which is a valid length for the TripleDES encoder we use below

			MD5CryptoServiceProvider hashProvider = new MD5CryptoServiceProvider();
			byte[] tdesKey = hashProvider.ComputeHash(utf8.GetBytes(passphrase));

			// Step 2. Create a new TripleDESCryptoServiceProvider object
			TripleDESCryptoServiceProvider tdesAlgorithm = new TripleDESCryptoServiceProvider();

			// Step 3. Setup the decoder
			tdesAlgorithm.Key = tdesKey;
			tdesAlgorithm.Mode = CipherMode.ECB;
			tdesAlgorithm.Padding = PaddingMode.PKCS7;

			// Step 4. Convert the input string to a byte[]
			byte[] dataToDecrypt = Convert.FromBase64String(encryptedText);

			// Step 5. Attempt to decrypt the string
			try
			{
				ICryptoTransform decryptor = tdesAlgorithm.CreateDecryptor();
				results = decryptor.TransformFinalBlock(dataToDecrypt, 0, dataToDecrypt.Length);
			}
			catch
			{
				results = Encoding.ASCII.GetBytes("fail");
			}
			finally
			{
				// Clear the TripleDes and Hashprovider services of any sensitive information
				tdesAlgorithm.Clear();
				hashProvider.Clear();
			}

			// Step 6. Return the decrypted string in UTF8 format
			return utf8.GetString(results);
		}


		/*
		 *  Twipler specific code
		 */

		private const string StartsWith = "ok";
		private const string EndsWith = "23";

		public static string Encrypt(this OAuthToken token, string password)
		{
			string formattedOauth = string.Format("{0} {1} {2} {3}", StartsWith, token.Token, token.TokenSecret, EndsWith);
			return EncryptString(formattedOauth, password);
		}

		public static OAuthToken Decrypt(this OAuthToken token, string encrypted, string password)
		{
			string oauthBlah = Encryption.DecryptString(encrypted, password);

			if (oauthBlah.StartsWith(StartsWith + " ") && (oauthBlah.EndsWith(" " + EndsWith)))
			{
				string[] bits = oauthBlah.Split(' ');
				if (bits.Length == 4)
					return new OAuthToken() {Token = bits[1], TokenSecret = bits[2]};
			}

			return token;
		}
	}
}
